import Foundation
import Flutter
/**
 * 功能描述:
 * 修改时间:
 * 修改描述:
 */
public class IMClient {
    
    private let TAG = String(describing:IMClient.self)
    //private let TAG = (NSStringFromClass(type(of: IMClient)))
    private static var INSTANCE:IMClient!
    
    //    @SuppressLint("StaticFieldLeak")
    private static var mAppContext:Any?;
    /**
     * 是否已经初始化mars
     */
    private var isInit = false;
    private var sysConfig:SysConfig?;
    private var initConfigInfo:InitConfigParams?;
    //存储flutter层传递的信息
    private var paramsMap:[String : Any]?;
    
//    typealias AppLogicCallBack = (_ btnTag : Int) -> Void
//    typealias StnLogicCallBack = (_ btnTag : Int) -> Void
//    typealias SdtLogicCallBack = (_ btnTag : Int) -> Void

    private var appLogicCallBack:AppLogicCallBack!;
    private var stnLogicCallBack:StnLogicCallBack!;
    private var sdtLogicCallBack:SdtLogicCallBack!;
    /**
     * 当前状态是否在房间内
     */
    private var isInRoom = false;
    /**
     * 是否登录socket成功
     */
    private var isLoginSuccess = false;
   // private var connectionReceiver:BaseEvent.ConnectionReceiver ;
//    private func IMClient() {
//        appLogicCallBack = AppLogicCallBack();
//        stnLogicCallBack = StnLogicCallBack();
//        sdtLogicCallBack = SdtLogicCallBack();
//    }
    private var lastTaskArray=[Any]();

    
    init() {
        appLogicCallBack = AppLogicCallBack();
        stnLogicCallBack = StnLogicCallBack();
        sdtLogicCallBack = SdtLogicCallBack();
    }
    
    public static func  getInstance()->IMClient {
        
        if INSTANCE == nil {
            INSTANCE = IMClient.init();
        }
        
        return INSTANCE
    }

    
   
    /**
     * 业务登录成功后调用IM初始化
     * 调用该方法前确保已经获取了存储权限
     * 登录socket
     *
     * @param context
     * @param sysConfig 系统配置
     * @param params    初始化参数
     * @param result
     * @param callback
     */
    public func initIMClient( sysConfig:SysConfig?, params:InitConfigParams?,map: [String:Any], result:FlutterResult, callback:Any) {
        
        paramsMap = map;
        
        //synchronized
        let Queue = DispatchQueue.init(label: "im.IMClient.initIMClient")
        Queue.sync {
            
            // mAppContext = context.getApplicationContext();
            
            //初始化xlog
//            XLogWrapper.getInstance().initXlogWrapper(isConsoleLogOpen:sysConfig != nil && ((sysConfig?.isConsoleLogOpen) != nil));
            
            if (sysConfig == nil || !sysConfig!.checkData() || params == nil || !params!.checkData()) {
                IMLog.e(tag:TAG, msg:"init() initConfigInfo data is error");
                result(ResultCode.PARAMS_ERROR);
            } else {
                if (isInit) {
                    onDestroy();
                }
                self.sysConfig = sysConfig;
                self.initConfigInfo = params;
                self.stnLogicCallBack.setInitConfigInfo(initConfigInfo: params);
                self.stnLogicCallBack.setMsgCallback(msgCallback: callback as AnyObject);
                
                IMLog.i(tag:TAG, msg:"\ninit() sysConfig:\(String(describing: sysConfig?.toString()))\ninitConfigInfo:\(String(describing: params?.toString()))");
                
                //初始化stn组件
//                AppLogic.setCallBack(appLogicCallBack);
//                StnLogic.setCallBack(stnLogicCallBack);
//                SdtLogic.setCallBack(sdtLogicCallBack);
                
                NetworkService.sharedInstance()?.delegate = stnLogicCallBack;
                NetworkService.sharedInstance()?.setCallBack()
                NetworkService.sharedInstance()?.createMars()
                NetworkService.sharedInstance()?.setClientVersion(200)
                NetworkService.sharedInstance()?.setLongLinkAddress(sysConfig!.ip, port: UInt16(sysConfig!.port))
                NetworkService.sharedInstance()?.reportEvent_(onForeground: true)
                NetworkService.sharedInstance()?.makesureLongLinkConnect()
                NetworkStatus.sharedInstance()?.start(NetworkService.sharedInstance())
                CommandUtils.initMap()
                
               // stnLogicCallBack.getLongLinkIdentifyCheckBuffer()
                registerReceiver();
                
                isInit = true;
                
                let array = NSMutableDictionary();
                array["success"] = (ResultCode.SUCCESS);
                result(array);
                
                IMLog.i(tag:TAG, msg: "init finish");
            }
            
        }
    }

    /**
     * 注册网络变化监听
     */
    private func registerReceiver() {
//        if (mAppContext != nil) {
//           var connectionReceiver =  BaseEvent.ConnectionReceiver();
//            var intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
//            mAppContext.registerReceiver(connectionReceiver, intentFilter);
        //}
        
        NetworkStatus.sharedInstance().start(NetworkService.sharedInstance())
    }

    /**
     * 反注册注册网络变化监听
     */
    private func unRegisterReceiver() {
//        if (mAppContext != nil && connectionReceiver != nil) {
//            mAppContext.unregisterReceiver(connectionReceiver);
//            connectionReceiver = nil;
//        }
        NetworkStatus.sharedInstance()?.stop()

    }

    private func isInit(methodName:String) ->Bool{
     
    //synchronized
        let Queue = DispatchQueue.init(label: "im.IMClient.isInit")
        Queue.sync {
            if (!isInit) {
                IMLog.e(tag:TAG,msg: "call \(methodName)(),IM not initialized!!!");
            }
        }
        
        return isInit && (sysConfig != nil) && (initConfigInfo != nil);

    }
    /**
     * 发送消息
     *
     * @param content 待发送消息文本(已经非空校验了)
     * @param roomId
     * @param result
     */
    public func sendRoomMsg( content:String,  roomId:String,  result:@escaping FlutterResult) {
        if (isInit(methodName: "sendRoomMsg")) {
            IMLog.i(tag: TAG, msg: "sendRoomMsg");

            let msgBean = SendMsgBean();
            msgBean.setContent(content: content);
            msgBean.setRoomId(roomId: roomId);
            msgBean.setUserId(userId:(initConfigInfo?.userId)!);
            //( cmdId:int,msgBean:IMsg,  result:FlutterResult,  timeoutMs:int, isNeedServerResp:Bool)
            sendMsg(cmdId:ReqCmdID.CMDID_ROOM_SEND_MSG_REQ, msgBean:msgBean, result:result, timeoutMs:Const.SEND_MSG_TIMEOUT, isNeedServerResp:true);
        } else {
            
            var map:[String:Any] = [String:Any].init()
            map["code"] = ResultCode.NO_INIT
            result(map);
        }
    }
    
    
   
    
    

    public func getContext()->String {
        return "mAppContext";
    }


    public func isInitMars()->Bool {
//        var isInitM:Bool;
//        let serialQueue = DispatchQueue(label: "imClient.isInt")
//        serialQueue.sync {
//            // code
//            isInitM = isInit;
//        }
        
        return isInit;
    }

    /**
     * 房间内发送自定义命令:请求上下麦,踢人...
     *
     * @param cmdId            自定义命令
     * @param params           请求参数map
     * @param isNeedServerResp 当前发送的命令是否需要服务器响应
     * @param result
     */
    public func sendRoomCommand( cmdId:Int,  params:[String:Any],  isNeedServerResp:Bool,  result:@escaping FlutterResult) {
        if (isInit(methodName: "sendRoomCommand")) {
            IMLog.i(tag:TAG,msg:"sendRoomCommand");

            if (params == nil) {
                
                var map:[String:Any] = [:]
                map["code"] = ResultCode.PARAMS_ERROR
                result(map);
                
            } else {
                
                let msgBean =  SendCmdBean();
                msgBean.setParams(params:params);
                sendMsg(cmdId:cmdId, msgBean:msgBean, result:result, timeoutMs:Const.SEND_ACTION_TIMEOUT, isNeedServerResp:isNeedServerResp);
            }
        } else {
            
            
            var map:[String:Any] = [String:Any].init()
            map["code"] = ResultCode.NO_INIT
            result(map);
        }
    }

    /**
     * 进入房间
     *
     * @param roomId      进入的房间ID
     * @param isReconnect 0-非重连，1-断线重连进入
     *                    如果是客户端在房间断线重连，那么reconnect则为1，这个时候登陆房间的时候，不会重推系统公告，欢迎语等消息
     * @param result
     */
    public func enterRoom( roomId:String,isReconnect:Bool,result:@escaping FlutterResult) {
        if (isInit(methodName: "enterRoom")) {
            IMLog.i(tag:TAG, msg:"enterRoom roomId:\(roomId)");

            isInRoom = true;

            let msgBean =  EnterRoomBean();
            msgBean.setRoomId(roomId: roomId);
            msgBean.setReconnect(reconnect: isReconnect ? 1 : 0);

            sendMsg(cmdId: ReqCmdID.CMDID_ENTER_ROOM_REQ, msgBean: msgBean, result: result, timeoutMs: Const.LOGIN_ROOM_TIMEOUT, isNeedServerResp: true);
        } else {
            var map:[String:Any] = [String:Any].init()
            map["code"] = ResultCode.NO_INIT
            result(map);
        }
    }

    /**
     * 触发重连逻辑
     */
    public func reconnect() {
        if (isInit(methodName: "reconnect")) {
            IMLog.i(tag:TAG, msg:"reconnect");
            NetworkService.sharedInstance()?.reportEvent_(onForeground: true)
            NetworkService.sharedInstance()?.makesureLongLinkConnect()

        }
    }

    /**
     * 登出房间
     *
     * @param roomId 退出的房间ID
     * @param result
     */
    public func logoutRoom( roomId:String,  result:@escaping FlutterResult) {
        if (isInit(methodName: "logoutRoom")) {
            IMLog.i(tag: TAG, msg: "logoutRoom roomId:\(roomId)");

            isInRoom = false;

            let msgBean =  LogoutRoomBean();
            msgBean.setRoomId(roomId: roomId);
            //            //( cmdId:int,msgBean:IMsg,  result:FlutterResult,  timeoutMs:int, isNeedServerResp:Bool)

            sendMsg(cmdId:ReqCmdID.CMDID_LOGOUT_ROOM_REQ, msgBean:msgBean, result:result,timeoutMs: Const.LOGOUT_ROOM_TIMEOUT, isNeedServerResp:true);

        } else {
            
            var map:[String:Any] = [String:Any].init()
            map["code"] = ResultCode.NO_INIT
            result(map);
        }
    }

    /**
     * Mars发送消息
     *
     * @param cmdId     消息类型,参考{@link ReqCmdID}
     * @param msgBean   消息对象
     * @param result    回调
     * @param timeoutMs 任务超时时长ms
     */
    private func sendMsg( cmdId:Int,msgBean:IMsg,  result:@escaping FlutterResult,  timeoutMs:Int, isNeedServerResp:Bool) {
        
        /*
         @property(nonatomic) uint32_t taskid;
         @property(nonatomic) ChannelType channel_select;
         @property(nonatomic) uint32_t cmdid;
         @property(nonatomic, copy) NSString *cgi;
         @property(nonatomic, copy) NSString *host;
         */
        let task =  CGITask();
        task?.cmdid = UInt32(cmdId);
        task?.channel_select = ChannelType_LongConn;
        task?.limitFlow = false;
        task?.limitFrequency = false;
        //必须设置为true,否则会导致task超时断开连接,然后自动重连,导致死循环(已验证,必须)
        //因为精简了通信协议,协议废弃了mars内置的taskId,所以导致与taskId关联的功能不能使用
        task?.sendOnly = true;
        task?.needAuthed = false;
//        //设置透传字段
        task?.userContext = msgBean.msgId;

//        let taskWrapper = TaskWrapper(task:task!, msgBean:msgBean, result:result, timeOutMs:timeoutMs)
//        taskWrapper.isNeedServerResp = isNeedServerResp;
//        TaskHandler.getInstance().addTask(task:taskWrapper);
        NetworkService.sharedInstance()?.start(task, forUI: nil);
        //        StnLogic.startTask(task);
        
        if lastTaskArray.count<3 {
            lastTaskArray.append(task as Any)
        } else {
            lastTaskArray.remove(at: 0)
            lastTaskArray.append(task as Any)
        }
        
    }
    
    /**  新的
         * IM发送消息
         *
         * @param cmdId            消息码（对应IM通信协议，消息头最开始的4个字节）：根据IM服务器的定义，传递参数
         * @param msgMap           消息内容：根据IM服务器的定义，传递参数
         * @param sendTimeoutMs    消息发送超时设置（单位毫秒）：表示在指定时间内，消息如果没有发送成功，直接停止发送，并回调业务方，消息发送失败的状态
         * @param isNeedServerResp 客户端发送该消息是否需要服务器响应，如果不需要,发送完成后resultCallback直接回调成功状态
         * @param resultCallback   消息发送结果回调
         */
    public func sendMessageNew(cmdId:Int,params:[String:Any], sendTimeoutMs:CLong, isNeedServerResp:Bool,result:@escaping FlutterResult, callback:Any){
        if(isInit){
            
            IMLog.i(tag:TAG, msg:"sendMessageNEw  cmdId:\(cmdId)  msgMap:\(params)  sendTimeoutMs:\(sendTimeoutMs) isNeedServerResp:\(isNeedServerResp)");
 
            
            if ( params == nil) {
                IMLog.e(tag: TAG, msg:"sendMessage params error");
                result(ResultCode.IM_PARAMS_ERROR);
            }else{
            
                        //2022年3月10日新增：
                      //优先判断flutter层传递的msgMap是否包含msgId字段，
                      //如果flutter层已经传递了msgId，优先取flutter传递的msgId字段作为消息唯一标示
//                      String msgId = AdapterTgameUtils.getMsgIdForRequestParamsMap(msgMap);

                var msgId = params["msgId"];
                      //是否是从flutter层获取的msgId
//                      boolean isFlutterMsgId = msgId != null;
                if(msgId == nil){
                    msgId = MsgUtils.getUUID();
                }
                
             
                var paramsMut = params;
                if(!params.keys.contains("msgId")){
                    paramsMut["msgId"] = msgId;
                }

                if(paramsMut.keys.contains("content")){
                    var contentMap = paramsMut["content"] as![String:Any];
                   
                    if(params["msgId"] == nil){
                        contentMap["msgId"] = msgId;
                    }
                    
                    paramsMut["content"] = contentMap;
                
                }
                
                
                
                let task =  CGITask();
                task?.cmdid = UInt32(cmdId);
                task?.channel_select = ChannelType_LongConn;
                task?.limitFlow = false;
                task?.limitFrequency = false;
                //必须设置为true,否则会导致task超时断开连接,然后自动重连,导致死循环(已验证,必须)
                //因为精简了通信协议,协议废弃了mars内置的taskId,所以导致与taskId关联的功能不能使用
                task?.sendOnly = true;
                task?.needAuthed = false;
        //        //设置透传字段
                task?.userContext = msgId as! String;

//                let taskWrapper = TaskWrapper(task: task!, msgBean: msgBean, isNeedServerResp: isNeedServerResp, sendTimeoutMs: sendTimeoutMs, result: result);
                
                let  taskWrapper = TaskWrapper(task: task!, msgDic: paramsMut, isNeedServerResp: isNeedServerResp, sendTimeoutMs: sendTimeoutMs, result: result);
                
                
                taskWrapper.isNeedServerResp = isNeedServerResp;
                TaskHandler.getInstance().addTask(task:taskWrapper);
                NetworkService.sharedInstance()?.start(task, forUI: nil);
                //        StnLogic.startTask(task);
                
                if lastTaskArray.count<3 {
                    lastTaskArray.append(task as Any)
                } else {
                    lastTaskArray.remove(at: 0)
                    lastTaskArray.append(task as Any)
                }
                
                
              
            }
            
            
        }else{
            result(ResultCode.IM_NO_INIT_ERROR);
        }
    }
    

    /**
     * 退出登录时,或不在使用IM时调用销毁,销毁后必须重新初始化后才能使用
     */
    public func onDestroy() ->Bool {
        var destory:Bool;
        
//        let serialQueue = DispatchQueue(label: "imClient.onDestroy")
//        serialQueue.sync {
            
            if (isInit(methodName: "onDestroy")) {
                IMLog.i(tag: TAG, msg: "onDestroy()");
                
                if (stnLogicCallBack != nil) {
                    stnLogicCallBack.setInitConfigInfo(initConfigInfo: nil);
                    stnLogicCallBack.setMsgCallback(msgCallback: nil);
                }
                
                XLogWrapper.getInstance().appenderFlush();
                unRegisterReceiver();
                
                //停止并清除所有未完成任务
                TaskHandler.getInstance().clear();
                NetworkService.sharedInstance()?.destroyMars()
                //                StnLogic.clearTask();
                //                Mars.onDestroy();
                isLoginSuccess = false;
                isInRoom = false;
                sysConfig = nil;
                initConfigInfo = nil;
                isInit = false;
            }
            return true;
       // }
        
      //  return destory
    }

    public func getAppVersion()->String {
//        let serialQueue = DispatchQueue(label: "imClient.getAppVersion")
//        serialQueue.sync {
            // code
        return  "2.0.0";
            
//        }
    }

//    public func  getSystem()->String {
////        let serialQueue = DispatchQueue(label: "imClient.getSystem")
////        serialQueue.sync {
//        return sysConfig == nil ? "unknow" : sysConfig?.system as! String;
//
//        //}
//    }

    public  func getDeviceId() -> String{
        
//        let serialQueue = DispatchQueue(label: "imClient.getDeviceId")
//        serialQueue.sync {
        return "unknowId" 
//        }
    }
    
    /*
     * flutter层传递的登录参数
     */
    public  func getParame() -> [String:Any]{
        
        return paramsMap! ;
    }
    
    

    public func getClientType()->String {
        return Const.CLIENT_TYPE;
    }

    public func getIsInRoom()->Bool {
        return isInRoom;
    }

    /**
     * 设置当前是否在房间内
     * 调用时机:
     * 1.进入房间成功/失败
     * 2.退出房间成功/失败
     *
     * @param inRoom
     */
    public func setInRoom(inRoom:Bool) {
        isInRoom = inRoom;
    }

    public func getIsLoginSuccess() -> Bool{
        return isLoginSuccess;
    }

    public func setLoginSuccess(loginSuccess:Bool) {
        isLoginSuccess = loginSuccess;
    }
    
    
    /**
         * 获取IM连接状态
         *
         * @return
         */
//    public func IMConnectStatus() {
//        return "";
//        }
    
}
